[org 0x1000]

mov si, loading
call print

; 内存检测
check_memory:
    mov ax, 0
    mov es, ax
    xor ebx, ebx
    mov edx, 0x534D4150
    mov di, ards_buffer

    .next:
        mov eax, 0xE820
        mov ecx, 20
        int 0x15
        jc error
        add di, cx
        inc dword [ards_count]
        cmp ebx, 0
        jnz .next

    mov si, detecting
    call print
    ; 跳转到保护模式
    jmp prepare_protect_mode

prepare_protect_mode:
    cli ; 关闭中断
    ; 打开A20线
    in al, 0x92
    or al, 0b10
    out 0x92, al

    ; 加载GDT
    lgdt [gdt_ptr]

    ; 打开保护模式
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp dword code_selector:protect_enable

print:
    mov ah, 0x0E
    .next:
        mov al, [si]
        cmp al, 0
        jz .done
        int 0x10
        inc si
        jmp .next
    .done:
        ret

[bits 32]
protect_enable:
    ; 初始化数据段
    mov ax, data_selector
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x10000

    ; 读取kernel
    mov edi, 0x10000
    mov ecx, 10
    mov bl, 200
    call read_disk

    mov eax, 0x20220205; 内核魔数
    mov ebx, ards_count; ards 数量指针
;    ; 跳转到kernel
    jmp dword code_selector:0x10000

read_disk:
    ; edi存储内存位置
    ; ecx存储起始扇区位置
    ; bl存储扇区数量
    pushad; ax, cx, dx, bx, sp, bp, si, di

    ; 设置扇区数量为1
    mov dx, 0x1F2
    mov al, bl
    out dx, al

    ; 设置起始扇区为0
    mov al, cl
    inc dx  ; 0x1F3
    out dx, al ; 起始扇区低八位

    shr ecx, 8
    mov al, cl
    inc dx  ; 0x1F4
    out dx, al ; 起始扇区中八位

    shr ecx, 8
    mov al, cl
    inc dx  ; 0x1F5
    out dx, al ; 起始扇区高八位

    shr ecx, 8
    and cl, 0b1111
    inc dx  ; 0x1F6
    ; 设置为LBA模式
    mov al, 0b1110_0000
    or al, cl
    out dx, al

    inc dx  ; 0x1F7
    ; 设置为读硬盘模式
    mov al, 0x20
    out dx, al

    xor ecx, ecx
    mov cl, bl

    .read:
        push cx
        call .waits
        call .reads
        pop cx
        loop .read
        popad
        ret

    .waits:
        mov dx, 0x1F7
        ; 检测硬盘状态
        .check:
            nop
            nop
            nop
            in al, dx
            ; 检测是否数据准备完毕
            and al, 0b1000_1000
            cmp al, 0b0000_1000
            jnz .check
        ret

    .reads:
        mov dx, 0x1F0
        mov cx, 0x100     ; 512byte
        .readw:
            nop
            nop
            nop
            in ax, dx
            mov [edi], ax
            add edi, 2
            loop .readw
        ret

loading:
    db "Loading Onix......", 10, 13, 0
detecting:
    db "Detecting Memory Success", 10, 13, 0

error:
    mov si, .msg
    call print
    hlt
    jmp $
    .msg:
        db "Loading Error!", 10, 13, 0

memory_base equ 0
memory_limit equ ((1024 * 1024 * 1024 * 4) / (1024 * 4)) - 1

code_selector equ (1 << 3)
data_selector equ (2 << 3)

gdt_ptr:
    dw (gdt_end - gdt_base) - 1
    dd gdt_base
; NULL描述符
gdt_base:
    dd 0, 0
gdt_code:
    dw memory_limit & 0xFFFF
    dw memory_base & 0xFFFF
    db (memory_base >> 16) & 0xFF
    db 0b1001_1010
    db 0b11000000 | ((memory_limit >> 16) & 0xFF)
    db (memory_base >> 24) & 0xFF
gdt_data:
    dw memory_limit & 0xFFFF
    dw memory_base & 0xFFFF
    db (memory_base >> 16) & 0xFF
    db 0b1001_0010
    db 0b11000000 | ((memory_limit >> 16) & 0xFF)
    db (memory_base >> 24) & 0xFF
gdt_end:

ards_count:
    dd 0
ards_buffer: